#####################################################################
# $Id: DBEntry.pm,v 1.1.1.1 2006/03/20 04:08:45 jfb Exp $
#
# DBEntry.pm - base class for database entries
#
# Every object in the Epiphyte engine that requires permanent storage
# in the database is a subclass of the DBEntry class.  This class
# performs most of the necessary SQL magic to fetch and store objects
# to/from the Epiphyte database.
#
# Classes wishing to inherit from the DBEntry class must provide a
# description of the target table by declaring the `DBTABLE' variable
# within their namespace.  Here is a sample DBTABLE declaration for
# a table storing an ID and a string.
#
# $DBTABLE = {
# 	name	=> 'mytable',
#	prikey	=> 'id',
#	columns	=> [ 'id', 'name' ],
# };
#
#
#
#####################################################################

package Epiphyte::DBEntry;

use strict;
use vars qw(@ISA %DBTABLE $AUTOLOAD);

no strict 'refs';

use DBI;

use Data::Dumper;

use Epiphyte::Log;
use Epiphyte::Forum;


%DBTABLE = (
	name	=> 'dummy',
);

#####################################################################
# new - class method
#
# Fetch an entry from the database.
#####################################################################

sub new
{
	my ($class) = @_;

	my $self = {
		_dirty	=> 0,
	};


	return ($self);
}

#####################################################################
# fetch - object method
#
# Fetch an entry from the database.
#####################################################################

sub fetch
{
	my ($self, $id) = @_;
	my $class = ref($self);

	if (!$Epiphyte::DB::DBH) {
		Epiphyte->log(LOG_ERR, "cannot fetch object: database closed");
		return;
	}

	my $table = $class::DBTABLE->{name};
	my $key;

	my $query = "SELECT * FROM $table WHERE $key = $id";

	my $sth = $Epiphyte::DB::DBH->prepare($query);

	$sth->execute();

	my $res = $sth->fetchrow_hashref();

	return (1);
}

#####################################################################
# store - object method
#
# Store the data of an object in the database.  The operation only
# takes place if the object is marked as dirty.
#####################################################################

sub store
{
	my ($self) = @_;
	my $class = ref($self);

	return (1) if ($self->{_dirty} == 0);

	if (!$Epiphyte::DB::DBH) {
		Epiphyte->log(LOG_ERR, "cannot fetch object: database closed");
		return;
	}

	my $table = $class::DBTABLE->{name};

	my $query = "INSERT INTO $table VALUES();";
	my $sth = $Epiphyte::DB::DBH->prepare($query);
	if (!$sth) {
		Epiphyte->log(LOG_ERR, "failed to prepare query: ",
		    $Epiphyte::DB::DBH->errstr());
		return;
	}

	Epiphyte->log(LOG_INFO, "store query: $query");
#	$sth->execute();

	return (1);
}

#####################################################################
# fetch_all - object method
#
# Fetch all entries from the database.
#####################################################################

sub fetch_all
{
	my ($class, %param) = @_;
	my $nparam;
	my @args;
	my @obj;

	my $tab_desc = \%{"${class}::DBTABLE"};


	if (!defined($Epiphyte::DB::DBH)) {
		Epiphyte->log(LOG_ERR, "cannot fetch object: database closed");
		return;
	}

	my $table = $tab_desc->{name};

	my $query = "SELECT * FROM $table";
	if (%param) {
		$query .= "WHERE ",
		$nparam = 0;

		foreach(%param) {
			$nparam++;
			$query .= " AND " if ($nparam > 1);
			$query .= "$_ = ?";
			push(@args, $param{$_});
		}
	}

	my $sth = $Epiphyte::DB::DBH->prepare($query);
	if (!$sth) {
		Epiphyte->log(LOG_ERR, "failed to prepare statement");
		return;
	}

	Epiphyte->log(LOG_INFO, "fetch_all query: $query");
	$sth->execute(@args);

	while (my $ent = $sth->fetchrow_hashref()) {
		my $o = $class->new();
		foreach(keys(%$ent)) {
			$o->$_($ent->{$_});
		}
		$o->mark_clean();

		push(@obj, $o);
	}

	return (\@obj);
}
#####################################################################
# mark_clean - object method
#
# Mark the current object as being dirty (not in sync with the
# database entry).
#####################################################################

sub mark_clean
{
	my ($self) = @_;

	$self->{_dirty} = 0;
	return (1);
}

#####################################################################
# mark_dirty - object method
#
# Mark the current object as being dirty (not in sync with the
# database entry).
#####################################################################

sub mark_dirty
{
	my ($self) = @_;

	$self->{_dirty} = 1;

	return (1);
}

#####################################################################
# AUTOLOAD - object method
#
#####################################################################

sub AUTOLOAD
{
	my $self = shift();
	my $pkg = ref($self);

	my $call = $AUTOLOAD;
	$call =~ s/.*://;

	if (@_) {
		$self->{"_$call"} = shift();
		$self->{_dirty} = 1;
	}

	return $self->{"_$call"};
}

sub DESTROY
{
	my ($self) = @_;

	if ($self->{_dirty} == 1) {
		$self->store();
	}


}

1;
